package com.hup.minicontroller.common.netty.handler;

import com.alibaba.fastjson.JSON;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * 处理序列化和反序列化的类
 * 关于字段数据类型对数据体大小的影响:
 * .一般情况下反序列化时,不同类,或同类增加字段时,{@link JSONSerializer}都优于{@link JavaDefaultSerializer},
 * .字段是基本数据类型时,即使不显式赋值,都会增大数据大小
 * .字段是封装类,且不赋值时,{@link JavaDefaultSerializer} 会增大数据大小, {@link JSONSerializer}不会!
 * .仅加入default方法后,都不影响序列化后的数据大小
 *
 * @author hugan
 * @date 2021/4/28
 */
public interface SerializerHandler {
    /**
     * 序列化对象
     */
    byte[] serialize(Object object) throws IOException;

    /**
     * 反序列化对象
     */
    <T> T deserialize(Class<T> clz, byte[] bytes) throws IOException, ClassNotFoundException;

    /**
     * java原始的序列化和反序列化类;
     * .夸程序反序列化时,两个程序的类必须完全一样,否则会有异常;
     * .支持javax.swing.ImageIcon
     */
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    class JavaDefaultSerializer implements SerializerHandler {

        public static final SerializerHandler INSTANCE = new JavaDefaultSerializer();

        @Override
        public byte[] serialize(Object object) throws IOException {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            return baos.toByteArray();
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T deserialize(Class<T> clz, byte[] bytes) throws IOException, ClassNotFoundException {
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            Object object = ois.readObject();
            return (T) object;
        }
    }

    /**
     * JSON序列化和反序列化类;
     * .跨程序反序列化时,类之间不需要任何关联(包名,类名,属性等)
     * .不支持javax.swing.ImageIcon
     */
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    class JSONSerializer implements SerializerHandler {

        public static final JSONSerializer INSTANCE = new JSONSerializer();

        @Override
        public byte[] serialize(Object object) {
            return JSON.toJSONBytes(object);
        }

        @Override
        public <T> T deserialize(Class<T> clz, byte[] bytes) {
            return JSON.parseObject(bytes, clz);
        }
    }

}
